//module Register File, accommodate 32 GP-registers and some specific ones

module RegFile (addr_a, addr_b, addr_w, in_val, we, reset, out_a, out_b, clk);
  parameter reg_addr_size=5;
  parameter word_size=32;
  parameter gpr_num=32;

  parameter ADDR_ZERO=5'b0;
  parameter VAL_ZERO=32'b0;




  input [reg_addr_size-1:0] addr_a, addr_b, addr_w; // addresses
  input [word_size-1:0] in_val; // word that should be written into reg_file[addr_w]
  input clk; //global clock
  input we; //write enable
  input reset; //to init the registers
  output [word_size-1:0] out_a, out_b; // word that shoule be read from reg_file[addr_*]

  reg out_a;
  reg out_b;


  //a temporary counter for register file initialize
  reg [gpr_num-1:0] counter;




  //internal register storage
  reg [word_size-1:0] registers [gpr_num-1:0];


  //handler for signal reset
  always @ (reset) begin
    if(reset==1'b1) begin
      for(counter=0;counter<gpr_num;counter=counter+1) begin
          registers[counter]<=VAL_ZERO;
      end
    end
  end



  //when pos edge of the clock, awake and read data
  always @ (posedge clk) begin
      out_a<=registers[addr_a];
      out_b<=registers[addr_b];
  end

  //when neg edge of the clock, awake, check write enable and write
  always @ (negedge clk) begin
      if(we==1'b1) begin
        //check whether writer specifies r0
        if(addr_w!=ADDR_ZERO) begin
            registers[addr_w]<=in_val;
        end
      end

  end
endmodule // RegFile


//import the clock generator for simulation
// `include "clock.v"
//
//
//
// module reg_file_sim();
//   parameter reg_addr_size=5;
//   parameter word_size=32;
//   parameter gpr_num=32;
//   reg[reg_addr_size-1:0] addr_a, addr_b, addr_w;
//   reg[word_size-1:0] in_val;
//   reg we;
//   reg reset;
//
//   wire clk;
//   wire [word_size-1:0] out_a, out_b;
//
//
//
//
//
//   RegFile reg_file(addr_a, addr_b, addr_w, in_val, we, reset, out_a, out_b, clk);
//   ClockGen clock_gen(clk);
//
//
//   initial begin
//     $dumpfile("reg_file_sim.vcd");
//     $dumpvars(0,reg_file_sim);
//
//     //register monitor
//     $display("Time\tClk\tWe\tAddr_a\tAddr_b\tAddr_w\tIn_val\tOut_a\tOut_b");
//     $monitor("%g\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x",$time, clk, we, addr_a, addr_b, addr_w, in_val, out_a, out_b);
//
//     //init state
//     addr_a=0;
//     addr_b=0;
//     addr_w=0;
//     we=0;
//
//     //half cycle of the clock is 5
//     #1 reset=1; //reset the data
//     #1 reset=0;
//     #10
//     #2 addr_a=5'b10001;
//     #1 addr_b=5'b10100;
//     //test normal write
//     #2 we=1;
//     #1 addr_w=5'b10110;
//     #1 in_val=32'b1;
//     #3 addr_a=5'b10110;
//     //test write disable
//     #1 we=0;
//     #1 in_val=32'hF00F0FFF;
//     //test write for reg 0
//     #8 addr_w=5'b0;
//     #1 we=1;
//     #1 addr_a=5'b0;
//     #9 $finish;
//
//   end
//
// endmodule //
